package com.gwnet.rider.service.impl;

import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.baomidou.lock.executor.RedissonLockExecutor;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.gwnet.rider.domain.RiderRegionRecord;
import com.gwnet.rider.service.DispatchService;
import com.gwnet.rider.service.RiderRegionRecordService;
import com.gwnet.rider.service.RiderUserService;
import com.gwnet.shop.domain.OrderDelivery;
import com.gwnet.shop.domain.OrderInfo;
import com.gwnet.shop.enums.DevStatusEnum;
import com.gwnet.shop.enums.OrderStatusEnum;
import com.gwnet.shop.service.IOrderDeliveryService;
import com.gwnet.shop.service.IOrderInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * 派单服务类，通过算法派送给外卖员
 *
 * @author: WangLiang
 * @date: 2024/8/1 17:08
 */
@Slf4j
@Service
public class DispatchServiceImpl implements DispatchService {

    private final static String ORDER_TO_RIDER_KEY = "orderToRider:";

    private final IOrderInfoService orderInfoService;
    private final RiderUserService riderUserService;
    private final RiderRegionRecordService regionRecordService;
    private final IOrderDeliveryService deliveryService;
    private final LockTemplate lockTemplate;

    public DispatchServiceImpl(IOrderInfoService orderInfoService, RiderUserService riderUserService, RiderRegionRecordService regionRecordService, IOrderDeliveryService deliveryService, LockTemplate lockTemplate) {
        this.orderInfoService = orderInfoService;
        this.riderUserService = riderUserService;
        this.regionRecordService = regionRecordService;
        this.deliveryService = deliveryService;
        this.lockTemplate = lockTemplate;
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean orderToRider(String orderId) {
        // 查询订单详情
        OrderInfo orderInfo = orderInfoService.getById(orderId);


        // 配送信息
        OrderDelivery delivery = deliveryService.getById(orderInfo.getDeliveryId());
        // 配送单已经不是待接单状态了，不能继续走接单流程，万一谁抢单抢走了呢
        if(ObjectUtils.isNotEmpty(delivery.getDeliveryStatus()) && !delivery.getDeliveryStatus().equals(DevStatusEnum.WAIT_RECEIVE_ORDER)){
            return false;
        }

        // 查询该区域的负责人ID
        LambdaQueryWrapper<RiderRegionRecord> regionQuery = new LambdaQueryWrapper<>();
        // 未来配送信息中会包含楼号，届时将筛选范围缩小到楼号，此时先按学校ID过滤
        regionQuery.eq(RiderRegionRecord::getSchoolId, orderInfo.getSchoolId())
//                .eq(RiderRegionRecord::getRegionId,"范围ID")
        ;

        List<RiderRegionRecord> regionRecords = regionRecordService.list(regionQuery);
        // 该范围没有负责的骑手？那不是扯淡呢吗
        if(regionRecords.size() == 0){
            return false;
        }

        List<Long> riderIds = regionRecords.stream().map(RiderRegionRecord::getRiderId).collect(Collectors.toList());

        // 执行给用户派单，这里需要根据学校ID锁一下，派完单然后再放开
        String key = ORDER_TO_RIDER_KEY + orderInfo.getSchoolId();
        final LockInfo lockInfo = lockTemplate.lock(key, 30000L, 5000L, RedissonLockExecutor.class);
        if (null == lockInfo) {
            return false;
        }
        // 获取锁成功，处理业务
        try {
            // 查询这些骑手中手中没有待完成系统派单的用户
            List<Long> list = deliveryService.selectUnHavePlatformOrderRiderIdList(riderIds);
            // 没有可以派单的骑手了
            if(list.size() == 0){
                log.info("没有可以派单的骑手了,学校ID：{},订单ID：{}",orderInfo.getSchoolId(),orderId);
                return false;
            }

            // fixme 随机抽取一名幸运观众，然后派给他
            Long luckyDogId = getLuckyDog(list);
            delivery.setRiderId(luckyDogId);
            // 来源：1.抢单 2.平台派单
            delivery.setSource(2);
            // 配送状态 1 待接单 2 待到店 3 待取货 4 待送达 5 待收货 6 完成
            delivery.setDeliveryStatus(DevStatusEnum.WAIT_TO_STORE.code());
            deliveryService.updateById(delivery);

            // 更新主表状态
            orderInfo.setOrderStatus(OrderStatusEnum.WAIT_TO_STORE.code());
            orderInfoService.updateById(orderInfo);

        } finally {
            //释放锁
            lockTemplate.releaseLock(lockInfo);
        }
        return true;
    }


    /**
     * 随机抽取一名幸运骑手，把这单派给他
     * @param list
     * @return
     */
    private static Long getLuckyDog(List<Long> list){
        // 生成一个随机索引
        int index = ThreadLocalRandom.current().nextInt(list.size());

        // 使用随机索引获取List中的元素
        Long riderId = list.get(index);
        return riderId;
    }
}
